import React, {useCallback, useEffect, useRef, useState} from 'react';
import { notification, App } from 'antd';
import { useDispatch, useSelector } from 'react-redux';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import { debounce, cloneDeep } from 'es-toolkit';

import PrivateRoute from '@/hooks/PrivateRoute';
import Loading from '@/components/Loading';
import { baseRouters, pageRouters } from "@/router";
import { flatRoutes, mapMenuAddKey, addDynamicRoute, getMenuData } from '@/utils/routeUtils';
import LayoutLoader from '@/layout';
import { VALIDATE, NOTFOUND, HOME } from '@/config/url';
import { EE, UN_LOGIN } from '@/utils/emitter';
import { validate, getWxOpenId, loginOpenId } from './service/base';
import { setStore } from '@/reducers/common';
import { getKeyFromUrl, removeKeyForUrl, isWx } from '@/utils';

export default (props) => {
    const initRouter = mapMenuAddKey(baseRouters);
    const initState = () => ({
        loading: true,
        routerTree: initRouter,
        routerArray: flatRoutes(initRouter),
    });
    const [state, setState] = useState(initState);
    const dispatch = useDispatch();
    const [api, contextHolder] = notification.useNotification();
    const { message } = App.useApp();

    /**
     * 监听sse通知
     * fetchEventSource 已内置重连逻辑
     */
    const notifyConnect = (user_id='') => {};
    /**
     * 活动弹框处理
     * 一天弹出一次
     */
    const activeVisible = () => {};
    /**
     * 通用处理 - 登录前
     */
    const initCommonBefore = async () => {
        // 设置本地存储
        const inviter = getKeyFromUrl('inviter') || '';
        if(inviter) {
            localStorage.setItem('_invitation', inviter);
            location.href = removeKeyForUrl(['inviter']);
        }
    };
    /**
     * 通用处理 - 登录后
     */
    const initCommonAfter = async () => {};
    /**
     * 检查用户是否登录（也可以获取用户信息）
     *
     */
    const initiateApplication = async () => {
        try{
            const response = await validate();
            const userInfo = response?.data || {};
            // pageRouters里的code可能是url，也可能是xx:xxx；权限全部放开，所以采用 pageRouters，否则不能使用
            const authSource = userInfo?.modules || pageRouters || []; // modules数据结构见router.jsx；后端返回的数据，也可以 router/index.jsx 中定义
            const authRouters = addDynamicRoute(authSource); // 动态处理路由，后端返的数据没有component，code转component且code转url
            const routerTree = mapMenuAddKey(baseRouters.concat(authRouters)); // 数据增加key，原始路由数据
            const routerArray = flatRoutes(routerTree); // 应用的所有路由，将tree打平成数组
            // menu 数据一般都在管理后台使用
            const canUseMenuTree = getMenuData(cloneDeep(routerTree), authSource); // 可以展示的菜单，showInMenu 且 有权限
            const menuTree = mapMenuAddKey(canUseMenuTree);
            const menuArray = flatRoutes(cloneDeep(menuTree));

            window.SITE_CONFIG['appMenuTree'] = menuTree;
            window.SITE_CONFIG['appMenuArray'] = menuArray;
            window.SITE_CONFIG['appRouterTree'] = routerTree;
            window.SITE_CONFIG['appRouterArray'] = routerArray;

            // redux记录用户信息
            dispatch(setStore({userInfo}));
            setState(o => ({ ...o, loading: false, routerArray, routerTree }));

            // 登录后，开始订阅接受通知
            if(!!userInfo.id) {
                notifyConnect(userInfo.id);

                // 登录后请求数据
                initCommonAfter(userInfo);
            }
        }catch(e){
            setState(o => ({ ...o, loading: false }));
        }finally{
            // 显示活动弹框
            activeVisible();
        };
    };
    /**
     * 微信一键登录重定向，拦截code登录
     *
     * @param {string} [code='']
     */
    const wxDirectLogin = (code='') => {
        let invitation = localStorage.getItem('_invitation') || '';

        function showBind(openId='', inviterCode='') {
            dispatch(setStore({
                loginVisible: false,
                bindVisible: true,
                bindType: 'sms',
                forceBindPhone: true,
                forceBindOpenId: openId,
                forceBindInviterCode: inviterCode,
            }));
        }

        getWxOpenId({code, invitation}).then(res => {
            if(OK_CODE === res?.code) {
                localStorage.removeItem('_invitation');

                loginOpenId({openId: res?.data, inviterCode: invitation}).then(respond => {
                    if(OK_CODE === respond?.code) {
                        const {token, user: userInfo, openId, inviterCode, expire} = respond || {};
                        // 强制绑定手机
                        const phone = userInfo?.phone || '';
                        if(!phone && (openId || userInfo?.accountOpenId)) return showBind(openId || userInfo?.accountOpenId, inviterCode);

                        // 设置token等信息后再跳转
                        localStorage.setItem('accessToken', token);
                        localStorage.removeItem('inviter_code');

                        location.href = removeKeyForUrl(['code']); // 这里不管怎么跳都需要去掉code，不然会重复请求
                    }else{
                        message.warning(respond?.msg || respond?.message || '');
                    }
                }).catch(e => {
                    message.error(e?.msg || e?.message || '');
                });
            }else{
                message.warning(res?.msg || res?.message || '请重新登录');
            }
        }).catch(e => {
            message.error(e?.msg || e?.message || '请重新登录');
        });
    };
    /**
     * 处理未登录事件
     *  本应用未登录时需要弹出登录框，其他应用可能是跳登录页，也可能是登录页和弹框共存
     *  这里可以额外传参数决定是采用哪种方式
     */
    const handleUnLogin = (params) => {
        if(VALIDATE === params.url) return;

        dispatch(setStore({loginVisible: true}));
    };

    // 这是入口文件，页面间切换不会触发，只有应用首次加载时才会触发
    useEffect(() => {
        // 设置全局变量，需要先设置，以防登录校验失败后无值
        window.SITE_CONFIG['appMenuTree'] = [];
        window.SITE_CONFIG['appMenuArray'] = [];
        window.SITE_CONFIG['appRouterTree'] = state.routerTree;
        window.SITE_CONFIG['appRouterArray'] = state.routerArray;

        // 初始化一些通用配置
        initCommonBefore();

        // 微信一键登录
        const wxCode = getKeyFromUrl('code') || '';
        if((isWx() && wxCode)) wxDirectLogin(wxCode);

        // 判断是否登录
        initiateApplication();

        // 订阅UN_LOGIN事件
        EE.on(UN_LOGIN, handleUnLogin);

        return () => {
            EE.off(UN_LOGIN);
        };
    }, []);

    return (
        <>
            {
                state.loading ?
                    <Loading/>
                    :
                    <Router>
                        <LayoutLoader>
                            <Switch>
                                {
                                    (state.routerArray || []).map(item => {
                                        return <PrivateRoute
                                            key={item.url}
                                            path={item.url}
                                            component={item.component}
                                            exact
                                            sensitive={false} // 路径不区分大小写
                                        />
                                    })
                                }

                                {/* 兜底404路由 - 上面路由都没匹配 */}
                                <Route
                                    render={(props) => {
                                        const routeArray = window.SITE_CONFIG['appRouterArray'] || [];
                                        const pathname = props?.location?.pathname;
                                        const NotFoundComp = baseRouters.find(i => i.url === NOTFOUND)?.component || null;

                                        /*
                                            管理后台一般都是登录后自动重定向到默认着陆页
                                            门户类网站会有根路径对应的首页
                                        */
                                        if(HOME === pathname) {
                                            const rootUrl = routeArray.find(i => i.index)?.url;
                                            if(!rootUrl) return <div>未设置着陆页</div>;

                                            return <Redirect to={rootUrl}/>;
                                        }

                                        // 无匹配路由展示404
                                        return <NotFoundComp  {...props} />;
                                    }}
                                />
                            </Switch>
                        </LayoutLoader>
                    </Router>
            }

            {contextHolder}
        </>
    );
};


